//
// Stochastic epidemic model implementation of the epidemic state 
// of one AS.
//
// @author Michael Liljenstam, ISTS, Dartmouth College
//
// $Id: StochasticWormEpidemicState.java,v 1.1 2003/03/08 03:23:41 mili Exp mili $

package SSF.App.Worm;

import com.renesys.raceway.SSF.*;
import SSF.Util.Random.*;
import cern.jet.random.*;


//.............................................................
/**
 *  Stochastic epidemic model implementation epidemic model.
 *  Contains epidemic state of one AS.
 *  See <tt>update()</tt> method for more information.
 */
public class StochasticWormEpidemicState extends WormEpidemicState {

    boolean DEBUG = false;

    public StochasticWormEpidemicState(AS myAS) {
	super(myAS);
    }

    /**
     *  One timestep update. 
     *  Calculate probability of hitting a susceptible host in this AS
     *  as <i>P[hit] = Beta_j * s</i>. 
     *  Where <i>Beta_j = ip_space_j / tot_ip_space * Beta</i>.
     *  Then the number of newly infected hosts in this AS is 
     *  <i>di = </i>Binomial(<i>n, P[hit]</i>), where <i>n</i> is the number 
     *  of scans hitting this AS in this timestep.
     */
    public void update(float iTot) {
	// refs to global data
	int numASs = MacroscopicModel.ref.net.numASs;
	float[] BetaJ = MacroscopicModel.ref.wormModel.BetaJ;
	float DeltaT = MacroscopicModel.ref.DeltaT;
	float t = MacroscopicModel.ref.t;
	float gamma = ((StochasticWormEpidemic)MacroscopicModel.ref
		.wormModel).gammaFctn.gamma(t, i, iTot);
	int j = myAS.index;

	// probability of hitting a susceptible host in this AS
	float pHit = iTot * BetaJ[j] * DeltaT;
	// # new infections has Bin(s, P[hit]) distribution
	// but avoid case where s=0 (no susceptibles left), illegal Bin() arg
	// also avoid cases where 0<s<1, but this will only occur if s_0 was 
	// initialized to a non-integer
	int newInfections;
	if (s >= 1) {
	    try {
 		MacroscopicModel.ref.infBinomialDistr = 
 		    new Binomial((int) Math.round(s), pHit, 
 				 MacroscopicModel.ref.infRNG);
 	    } catch (java.lang.IllegalArgumentException e) {
 		System.err.println("StochasticWormEpidemicState: Bad parameters to Binomial distribution, Bin(" + s + "," + pHit + ")\n");
 		throw e;
 	    }
	    MacroscopicModel.ref.infBinomialDistr = 
		new Binomial((int) Math.round(s), pHit, 
			     MacroscopicModel.ref.infRNG);
	    newInfections = MacroscopicModel.ref.infBinomialDistr.nextInt();
	} else {
	    newInfections = 0;
	}

	float next_s = s - newInfections;
	float next_i = i + newInfections - gamma;
	float next_r = r + gamma;

	/*	if (DEBUG) {
		System.out.println("t: "+t+" AS "+myAS.asNumber+" before: s="+s+", i="+i+", r="+r
		+" - after: s="+next_s+", i="+next_i+", r="+next_r);
		} */

	// trigger infections in hosts
	myAS.triggerInfections((int) Math.floor(next_i 
						- myAS.triggeredInfections));

	// separate for clarity
	s = next_s; i = next_i; r = next_r;

    } // update

    public void output() {
	System.out.print("  " + s + "  " + i + "  " + r);
    }

} // class StochasticWormEpidemicState


